#include "volume.merger.h"

#include "tools.filesystem.h"

namespace jolfs
{

MergerVolume::MergerVolume( const std::string& name )
  : Volume( name )
{
  root_.setParent( 0 );
  root_.setName( name );
  root_.setSize( 0 );
  root_.setMode( UMODE(1,0,0) | GMODE(1,0,0) | OMODE(1,0,0) ); //TODO: fix this
  root_.setType( Entry::DIRECTORY );
  root_.setStatus( 0 );           //TODO: fix this
  root_.setAccessTime( 0 );       //TODO: fix this
  root_.setModificationTime( 0 ); //TODO: fix this
  root_.setCreationTime( 0 );     //TODO: fix this
}

MergerVolume::MergerVolume( const MergerVolume& other )
  : Volume( other ),
    mergedVolumes_( other.mergedVolumes_ )
{
}

MergerVolume::~MergerVolume()
{
}

const VolumeList& MergerVolume::getMergedVolumes() const
{
  return mergedVolumes_;
}

VolumeList& MergerVolume::getMergedVolumes()
{
  return mergedVolumes_;
}

void MergerVolume::addMergedVolume( Volume* volume )
{
  VolumeList::const_iterator it = std::find( mergedVolumes_.begin(), mergedVolumes_.end(), volume );
  if ( it == mergedVolumes_.end() )
  {
    root_.addChild( volume->getRoot() );    // Add the entry to our root virtual directory
    volume->getRoot()->setParent( &root_ ); // Set the parent of the volume's root to our root
    mergedVolumes_.push_back( volume );     // Remember the volume
  }
  // TODO: handle 'else' error -> cannot merge two volumes of the same name.. or can we ? then we should recursively
  //       create merger volumes to mix entries
}

void MergerVolume::delMergedVolume( Volume* volume )
{
  VolumeList::iterator it = std::find( mergedVolumes_.begin(), mergedVolumes_.end(), volume );
  if ( it != mergedVolumes_.end() )
  {
    root_.delChild( (*it)->getRoot() ); // Our root should forget the to-be-deleted volume's root
    (*it)->getRoot()->setParent( 0 );   // Notify the volume's root that we are no longer its parent
    mergedVolumes_.erase( it );         // Forget the volume
  }
}

void MergerVolume::addEntry( Entry* )
{
  //TODO: hmm... what to do ?
}

EntryList MergerVolume::getEntries() const
{
  EntryList result;
  
  VolumeList::const_iterator it = mergedVolumes_.begin();
  for (; it!=mergedVolumes_.end(); ++it )
    result.push_back( (*it)->getRoot() );
  
  return result;
}

Entry* MergerVolume::getRoot()
{
  return &root_;
}

const Entry* MergerVolume::getRoot() const
{
  return &root_;
}

const Entry* MergerVolume::getEntry( const std::string& path ) const
{
  if ( path.empty() || path=="/" )
    return &root_;
  
  std::vector<std::string> tokenized_path = explode(path);
  
  if ( tokenized_path.empty() ) //should not happen
    return 0;
  
  VolumeList::const_iterator it = mergedVolumes_.begin();
  for (; it!=mergedVolumes_.end(); ++it )
  {
    if ( (*it)->getName()==tokenized_path.at(0) )
    {
      if ( tokenized_path.size()==1 )
        return (*it)->getRoot();
      else
      {
        tokenized_path = std::vector<std::string>( tokenized_path.begin()+1, tokenized_path.end() );
        return (*it)->getEntry( implode(tokenized_path) );
      }
    }
  }
  return 0;
}

Entry* MergerVolume::getEntry( const std::string& path )
{
  if ( path.empty() || path=="/" )
    return &root_;
  
  std::vector<std::string> tokenized_path = explode(path);
  
  if ( tokenized_path.empty() ) //should not happen
    return 0;
  
  VolumeList::iterator it = mergedVolumes_.begin();
  for (; it!=mergedVolumes_.end(); ++it )
  {
    if ( (*it)->getName()==tokenized_path.at(0) )
    {
      if ( tokenized_path.size()==1 )
        return (*it)->getRoot();
      else
      {
        tokenized_path = std::vector<std::string>( tokenized_path.begin()+1, tokenized_path.end() );
        return (*it)->getEntry( implode(tokenized_path) );
      }
    }
  }
  return 0;
}

} // namespace jolfs